import cv2
import threading
import numpy as np
from typing import Optional
from utils.Logger import Logger
from config.window_settings import WindowConfig
from config.message_constants import CameraMessages

class CameraController:
    def __init__(self, status_callback=None, frame_callback=None, logger: Optional[Logger] = None, module: str = "Camera"):
        """
        多线程摄像头控制器

        参数说明：
        :param status_callback: 状态变更回调函数
        :param frame_callback: 新帧到达回调函数（接收RGB帧）
        :param logger: 日志记录器实例
        """
        # 线程安全锁，保护帧缓冲区
        self._frame_lock = threading.Lock()
        # 当前最新帧缓存（RGB格式）
        self._current_frame: Optional[np.ndarray] = None
        # 视频采集线程实例
        self._capture_thread: Optional[threading.Thread] = None
        # 线程停止信号标志
        self._stop_event = threading.Event()
        # 默认请求分辨率（宽，高）
        self._request_size = (1920, 1080)
        # 多个控制器采用同一个日志记录器
        self.logger = logger
        # 设置该模块名称
        self.module = module
        # 回调函数绑定
        self.status_callback = status_callback  # 状态变化回调
        self.frame_callback = frame_callback    # 新帧到达回调

    def __del__(self):
        """析构函数，确保资源正常释放"""
        self.stop_camera()

    def start_camera(self, width: int = 1920, height: int = 1080) -> bool:
        """
        初始化并启动摄像头采集线程
        
        参数说明：
        :param width: 请求的视频宽度
        :param height: 请求的视频高度
        :return: 是否成功启动
        """
        # 检查摄像头是否已在运行
        if self.is_running:
            self.logger.warning(CameraMessages.CAMERA_ALREADY_RUNNING,self.module)
            return True

        self.logger.info(CameraMessages.CAMERA_REQUEST_RESOLUTION.format(str(width),str(height)),self.module)

        # 初始化视频采集对象（Windows使用DSHOW）
        self._cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        if not self._cap.isOpened():
            self.logger.error(CameraMessages.CAMERA_OPEN_FAIL,self.module)
            return False

        # 设置分辨率（实际可能被摄像头固件限制）
        self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        
        # 启动采集线程
        self._stop_event.clear()
        self._capture_thread = threading.Thread(
            target=self._capture_loop,
            daemon=True,
            name="CameraCaptureThread"
        )
        self._capture_thread.start()
        self.logger.info(CameraMessages.CAPTURE_THREAD_STARTED,self.module)
        return True

    def _capture_loop(self):
        """采集线程主循环"""
        try:
            # 通知状态变更
            if self.status_callback:
                self.status_callback("CAMERA_ACTIVE")

            # 获取实际分辨率
            actual_width = int(self._cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            actual_height = int(self._cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.logger.info(CameraMessages.CAMERA_ACTUAL_RESOLUTION.format(str(actual_width),str(actual_height)),self.module)


            # 采集主循环
            while not self._stop_event.is_set():
                # 读取视频帧
                ret, frame = self._cap.read()
                if not ret:
                    self.logger.error(CameraMessages.FRAME_READ_FAIL,self.module)
                    if not self._reopen_camera():
                        break  # 重试失败则退出循环
                    continue

                try:
                    # 转换颜色空间 BGR -> RGB
                    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

                    # 执行帧回调（传递RGB副本）
                    if self.frame_callback:
                        self.frame_callback(rgb_frame.copy())
                    
                    # 更新当前帧缓存(存储为RGB格式)
                    with self._frame_lock:
                        self._current_frame = rgb_frame.copy()

                except Exception as e:
                    self.logger.error(CameraMessages.FRAME_PROCESS_ERROR.format(str(e)),self.module)

        except Exception as e:
            self.logger.error(CameraMessages.CAPTURE_THREAD_ERROR.format(str(e)),self.module)
            if self.status_callback:
                self.status_callback("CAMERA_ERROR")

        finally:
            # 清理资源
            self._cap.release()
            self._cap = None
            self.logger.info(CameraMessages.CAMERA_INACTIVE,self.module)
            if self.status_callback:
                self.status_callback("CAMERA_INACTIVE")

    def _reopen_camera(self) -> bool:
        """
        尝试重新初始化摄像头设备(指数退避重连策略)
        
        返回说明：
        :return: 是否重连成功
        """
        retry_intervals = [1, 2, 4, 8]  # 重试间隔(秒)
        for idx, interval in enumerate(retry_intervals):
            try:
                time.sleep(interval)
                self.logger.info(CameraMessages.CAMERA_RECONNECTING.format(str(idx+1)), module=self.module)
                if self._cap:
                    self._cap.release()
                self._cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
                if self._cap.isOpened():
                    self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._request_size[0])
                    self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._request_size[1])
                    return True
            except Exception as e:
                self.logger.error(CameraMessages.CAMERA_RECONNECT_FAIL.format(str(e)), module=self.module)
        return False

    def stop_camera(self):
        """安全停止采集线程"""
        if self._capture_thread and self._capture_thread.is_alive():
            self.logger.info(CameraMessages.CAMERA_STOPPING,self.module)
            # 设置停止标志
            self._stop_event.set()
            # 等待线程结束（最多2秒后强制终止）
            self._capture_thread.join(timeout=2.0)
            # 检查线程状态
            if self._capture_thread.is_alive():
                self.logger.warning(CameraMessages.THREAD_FORCE_TERMINATE,self.module)
            # 清理线程引用
            self._capture_thread = None

    def get_frame(self) -> Optional[np.ndarray]:
        """
        获取当前视频帧的副本（线程安全）
        
        返回说明：
        :return: RGB 格式的视频帧，如果没有帧则返回 None
        """
        with self._frame_lock:
            return self._current_frame.copy() if self._current_frame is not None else None

    def capture(self, filename: str) -> bool:
        """
        保存当前帧为图片文件
        
        参数说明：
        :param filename: 保存路径
        :return: 是否保存成功
        """
        # TODO: 截图功能待验证
        frame = self.get_frame()
        if frame is not None:
            try:
                # 转换颜色空间 RGB -> BGR（OpenCV保存需要）
                save_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
                cv2.imwrite(filename, save_frame)
                self.logger.info(CameraMessages.SUCCESS_SCREENSHOT.format(str(filename)),self.module)
                return True
            except Exception as e:
                self.logger.error(CameraMessages.FAIL_SCREENSHOT.format(str(e)),self.module)
        return False
    
    @property
    def is_running(self) -> bool:
        """
        摄像头运行状态
        
        返回说明：
        :return: True表示采集线程正在运行
        """
        return self._capture_thread is not None and self._capture_thread.is_alive()